package com.excel.validators.excel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.excel.validators.core.decorative.BasicClass;
import com.excel.validators.core.decorative.CompositeValue;
import com.excel.validators.core.decorative.FieldElement;
import com.excel.validators.core.decorative.FieldValue;
import com.excel.validators.core.decorative.inner.ExportEntry;
import com.excel.validators.core.exception.InstanceException;
import com.excel.validators.core.extension.TypeConverter;

/**
 * @author wangxiaoliang10
 * 
 * 写回excel数据（可用于批量处理错误提示消息）
 */
@SuppressWarnings("rawtypes")
public abstract class ExcelWriteHandler extends ExcelReadHandler implements ExportEntry {

	/**
	 * 是否已将错误消息写入到excel中
	 */
	private boolean hasWriteError = false;
	
	/**
	 * 颜色及样式
	 * @param excelFile
	 */
	private StyleClass styleClass;

	public ExcelWriteHandler() {
		super();
	}

	public ExcelWriteHandler(File excelFile, int worksheet) {
			super(excelFile, worksheet);
	}
	
	public ExcelWriteHandler(InputStream inStream) {
			super(inStream);
	}
	
	/**
	 * 将数据写回excel中
	 * @param sheet
	 */
	protected XSSFSheet echo(XSSFSheet sheet) {
			if (sheet == null)
					throw new NullPointerException("sheet can not be null");
			// loop row of sheet
			int rowIndex = getSkipHeader();
			// get model metedata
			Map<String, FieldElement> fieldEntry = get().getFieldEntry();
			for (CompositeValue composite : getComposites()) {
					XSSFRow xssfRow = sheet.getRow(rowIndex);
					for (FieldValue filed : composite) {
							XSSFCell cell = cellgetOrCreate(xssfRow,
									fieldEntry.get(filed.getFieldName()).getFieldIndex());
							if (filed.hasError()) {
									setErrorStyle(filed.getMessage(),cell);
							}
							setCellValue(filed,cell);
					}
					rowIndex ++;
			}
			return sheet;
	}
	
	// create new cell
	private XSSFCell cellgetOrCreate(XSSFRow xssfRow, int fieldIndex) {
			XSSFCell cell = xssfRow.getCell(fieldIndex);
			if (cell == null){
					cell = xssfRow.createCell(fieldIndex);
			}
			return cell;
	}

	/**
	 * 通过默认的模型导出为excel
	 * @return 
	 * @return
	 */
	protected <T> XSSFWorkbook translateEntitys(List<T> entitys) throws InstanceException {
				// TODO converting the model to excel
				Map<String, FieldElement> fieldEntry = get().getFieldEntry();
				try {
						return createWorkBook(fieldEntry, entitys);
				} catch (Exception e) {
						logger.error("create workbook instance error: " + e.getMessage(),e);
						throw new InstanceException("create workbook instance error: ", e.getMessage());
				}
	}
	
	/**
	 * 将随机模型导出为excel
	 */
	protected <T> XSSFWorkbook translateEntitys(Class<T> basicClass,List<T> entitys) throws InstanceException {
			// get dynamic class model metedata
			try {
					// set namespace
					super.analysisElement(basicClass);
					// add model
					Map<String, FieldElement> fieldEntry = get().getFieldEntry();
					return createWorkBook(fieldEntry, entitys);
			} catch (Exception e) {
					logger.error("create workbook instance error: " + e.getMessage(),e);
					throw new InstanceException("create workbook instance error: ", e.getMessage());
			}
	}
	
	/*
	 * 创建excel表格
	 */
	protected <T> XSSFWorkbook createWorkBook(Map<String, FieldElement> fieldEntry,List<T> entitys) {
			// volidate data content
			if (fieldEntry == null ||
					entitys == null || 
					fieldEntry.isEmpty() ||
					entitys.isEmpty()) {
					throw new IllegalArgumentException("data of entitys is none");
			}
			
			FieldElement[] fields = fieldEntry.values()
					.toArray(new FieldElement[fieldEntry.size()]);
			// create workbook
			XSSFWorkbook workbook = new XSSFWorkbook();
			XSSFSheet xssfsheet = workbook.createSheet();
			// create header with sheet
			createHeaders(fields,xssfsheet);
			// loop line content and translate to xssfRow
			int line = getSkipHeader();
			for (T entry : entitys) {
					XSSFRow createRow = xssfsheet.createRow( line++ );
					createRow(createRow,fields,entry);
			}
			return xssfsheet.getWorkbook();
	}
	
	/**
	 * 创建表头
	 * @param fields
	 * @param sheet
	 */
	private void createHeaders(FieldElement[] fields, XSSFSheet xssfsheet) {
			int headerline = getSkipHeader();
			// create a header by name
			XSSFRow header = xssfsheet.createRow(headerline != 0 ? headerline - 1 : 0);
			for (FieldElement field : fields) {
					XSSFCell createCell = header.createCell(field.getFieldIndex());
					createCell.setCellValue(field.getColumnName());
					// set header style
					setHeaderStyle(createCell,field);
			}
	}

	/**
	 * 创建行数据
	 * @param fields
	 * @param createRow 
	 * @param field
	 */
	private void createRow(XSSFRow createRow , FieldElement[] fields , Object instance) {
			if (instance == null) return;
			// TODO Auto-generated method stub
			for (FieldElement field : fields) {
					XSSFCell createCell = createRow.createCell(field.getFieldIndex());
					Object reflectValue = getReflectValue(instance, field);
					createCell.setCellValue(reflectValue != null ? reflectValue.toString() : "");
					setNewStyle(createCell);
			}
	}

	/*
	 * 注入属性值
	 */
	protected Object getReflectValue(Object instance, FieldElement field) {
			// reflect value from instance
			Field reflect = field.getReflect();
			Object object = null;
			try {
					object = reflect.get(instance);
					int basicClass = field.getBasicClass();
					if (basicClass == BasicClass.STRING) {
							return object;
					} else	if (basicClass == BasicClass.DATE) {
							object = object != null ? 
									TypeConverter.formatDate((Date)object,field.getPattern()) 
									: null;
					} else if (basicClass == BasicClass.BIGDECIMAL || 
							basicClass == BasicClass.FLOAT || 
							basicClass == BasicClass.DOUBLE ) {
							object = object != null ? 
									TypeConverter.toBigDecimal(object.toString(), field.getDecimal())
									: null;
					}
			} catch (Exception e) {
					logger.error("value get faild,check your defined: "
							+ "field name:" + field.getFieldName(),e);
			}
			return object;
	}
	
	/**
	 * 将读入的excel文件验证后，写回客户端
	 * @param file
	 * @return 
	 * @throws IOException
	 */
	@Override
	public void writeExcel(File file) throws IOException {
			FileOutputStream stream = new FileOutputStream(file);
			writeExcel(stream);
	}

	/**
	 * 将读入的excel文件验证后，写回客户端
	 * @param file
	 * @return 
	 * @throws IOException
	 */
	@Override
	public void writeExcel(OutputStream output) throws IOException {
			XSSFSheet xssfsheet;
			if (!hasWriteError) {
					xssfsheet = echo(getSheet());
			} else {
					xssfsheet = getSheet();
			}
			XSSFWorkbook workbook = xssfsheet.getWorkbook();
			workbook.write(output);
	}

	
	/**
	 * 通过默认的模型将entitys导出为excel文件
	 * @param file
	 * @throws IOException
	 * @throws InstanceException 
	 */
	@Override
	public <T> void exportEntitys(List<T> entitys , File newfile) throws IOException, InstanceException {
			FileOutputStream output = new FileOutputStream(newfile);
			exportEntitys(entitys, output);
	}
	
	/**
	 * 通过默认的模型将entitys导出为excel文件
	 * @param file
	 * @throws IOException
	 * @throws InstanceException 
	 */
	@Override
	public <T> void exportEntitys(Class<T> basicClass , List<T> entitys , File newfile) throws IOException, InstanceException {
			FileOutputStream output = new FileOutputStream(newfile);
			exportEntitys(basicClass, entitys, output);
	}
	
	/**
	 * 通过默认的模型将entitys导出为excel流数据
	 * @param file
	 * @throws IOException
	 * @throws InstanceException 
	 */
	@Override
	public <T> void exportEntitys(List<T> entitys , OutputStream output) throws IOException, InstanceException {
			XSSFWorkbook workbook = translateEntitys(entitys);
			workbook.write(output);
	}
	
	/**
	 * 通过默认的模型将entitys导出为excel流数据
	 * @param file
	 * @throws IOException
	 * @throws InstanceException
	 */
	@Override
	public <T> void exportEntitys(Class<T> basicClass , List<T> entitys , OutputStream output) throws IOException, InstanceException {
			XSSFWorkbook workbook = translateEntitys(basicClass,entitys);
			workbook.write(output);
	}
	
	protected StyleClass getStyleClass(XSSFCell cell) {
			// TODO set red cell styoe
			if (styleClass == null) {
					XSSFSheet xssfsheet = cell.getSheet();
					styleClass = new StyleClass(xssfsheet);
			}
			return styleClass;
	}
	
	/**
	 * 错误的单元格标红
	 * @param styleClass 
	 * @param audit
	 * @param cell
	 */
	private void setErrorStyle(String message, XSSFCell cell) {
			StyleClass styleClass = getStyleClass(cell);
			Comment comment = styleClass.creteComment(message);
			cell.setCellComment(comment);
			cell.setCellStyle(styleClass.getErrorCellStyle());
	}
	
	/*
	 * 设置单元格属性
	 */
	private void setNewStyle(XSSFCell cell) {
			// TODO set red cell styoe
			StyleClass styleClass = getStyleClass(cell);
			// create default column style
			XSSFCellStyle style = styleClass.getColumnStype();
			cell.setCellStyle(style);
	}
	
	/*
	 * 设置表头样式
	 */
	private void setHeaderStyle(XSSFCell cell,FieldElement field) {
			StyleClass styleClass = getStyleClass(cell);
			styleClass.setHeaderStyle(cell);
			if (field.getBasicClass() == BasicClass.DATE) {
					cell.getSheet().setColumnWidth(field.getFieldIndex(), 6144);
			} else {
					cell.getSheet().setColumnWidth(field.getFieldIndex(), 3072);
			}
	}
	
	private void setCellValue(FieldValue value, XSSFCell cell) {
			XSSFCellStyle cellStyle = cell.getCellStyle();
			cellStyle.setAlignment(XSSFCellStyle.ALIGN_RIGHT);
			cell.setCellValue(toString(value,cell));
	}
	
	/**
	 * 输出数据修改
	 * @param obj
	 * @return
	 */
	protected String toString(FieldValue field, XSSFCell cell) {
			String oldValue = field.getOldValue();
			Object newValue = field.getValue();
			if (oldValue != null && newValue == null) {
					setErrorStyle("数据格式不正确！", cell);
					return oldValue;
			}
			if (newValue != null) {
					return newValue instanceof Date ? oldValue : newValue.toString();
			}
			return field.getOldValue();
	}
	
	/**
	 * @author wangxiaoliang10
	 * 辅助类
	 */
	final class StyleClass {
		
		private XSSFWorkbook workbook;
		
		private Drawing drawing;
		
		private ClientAnchor anchor;
		
		private CreationHelper factory;
		
		private XSSFCellStyle cellStyle;
		
		private XSSFCellStyle headerStyle;
		
		final static String author = "JD Technical Support";

		public StyleClass(XSSFSheet xssfsheet) {
				this.workbook = xssfsheet.getWorkbook();
				this.factory = workbook.getCreationHelper();
				this.anchor = factory.createClientAnchor();
				this.drawing = xssfsheet.createDrawingPatriarch();
		}
		
		public StyleClass(XSSFSheet xssfsheet,boolean newstype) {
				this.workbook = xssfsheet.getWorkbook();
		}
		
		/*
		 * 初始化style
		 */
		private XSSFCellStyle createErrorStyle() {
				XSSFCellStyle cellStyle = workbook.createCellStyle();
				cellStyle.setFillPattern(XSSFCellStyle.FINE_DOTS);
				cellStyle.setFillForegroundColor(IndexedColors.RED.index); // 前景色为大红色
				cellStyle.setFillBackgroundColor(IndexedColors.RED.index);
				return cellStyle;
		}

		/*
		 * 设置表头特殊属性
		 */
		public void setHeaderStyle(XSSFCell createCell) {
				if (headerStyle == null) {
						headerStyle = workbook.createCellStyle();
						// 设置高度
						createCell.getRow().setHeightInPoints(40);
						// 水平垂直居中
						headerStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
						headerStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
						// 背景颜色
						headerStyle.setFillPattern(XSSFCellStyle.FINE_DOTS );
						headerStyle.setFillForegroundColor(IndexedColors.LIME.getIndex());	
						headerStyle.setFillBackgroundColor(IndexedColors.LIME.getIndex());
						// border
						headerStyle.setBorderBottom(XSSFCellStyle.BORDER_THIN); //下边框
						headerStyle.setBorderLeft(XSSFCellStyle.BORDER_THIN);//左边框
						headerStyle.setBorderTop(XSSFCellStyle.BORDER_THIN);//上边框
						headerStyle.setBorderRight(XSSFCellStyle.BORDER_THIN);//右边框
						// 字体
						XSSFFont font = workbook.createFont();		
						font.setFontHeightInPoints((short) 12);
						font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
						font.setFamily(0);
						font.setFontName("宋体");
						headerStyle.setFont(font);
				}
				createCell.setCellStyle(headerStyle);
		}
		
		/*
		 * 设置列样式属性
		 */
		protected XSSFCellStyle getColumnStype() {
				if (cellStyle == null) {
						cellStyle = workbook.createCellStyle();
						cellStyle.setAlignment(XSSFCellStyle.ALIGN_RIGHT); 	// 右对齐
						XSSFFont font = workbook.createFont();		// 字体
						font.setFontHeightInPoints((short) 12);
						font.setColor(IndexedColors.AUTOMATIC.getIndex());
						font.setFamily(0);
						font.setFontName("宋体");
						cellStyle.setFont(font);
				}
				return cellStyle;
		}
		
		/**
		 * 生成注释对象
		 * @param message
		 * @return
		 */
		public Comment creteComment(String message) {
				Comment comment = drawing.createCellComment(anchor);
				RichTextString error = factory.createRichTextString(message);
				comment.setString(error);
				comment.setAuthor(author);
				return comment;
		}

		/**
		 * 样式颜色
		 * @return
		 */
		public XSSFCellStyle getErrorCellStyle() {
				if (cellStyle == null) {
						cellStyle = createErrorStyle();
				}
				return cellStyle;
		}
		
	}
}